import type { MenuItem } from '../../../../../components/toolbar/types'
import type { ComponentStyleIdType } from '../../../../../types/interfaces'
import type {
  ActionHandler,
  GreasyForkStorageCategory,
  ScriptActionType,
} from '../../../../../user_center/tab/personalization/custom_css/theme/others/greasy_fork/module/storage_process/types'
import type { ScriptTagLabelsType } from '../../../../../user_center/tab/personalization/custom_css/theme/others/greasy_fork/page/lib/types'
import { Toolbar } from '../../../../../components/toolbar'
import { BaseModule } from '../../../../../lib/abstract'
import { PageHandler } from '../../../../../lib/page_handler'
import {
  BodyClasses,
  ComponentStyleId,
  logger,
  loggerDeduplicator,
  MODULE_CONFIG,
} from '../../../../../types/constants'
import { GREASY_FORK_PAGE_ELEMENTS } from '../../../../../types/constants/personalization/greasy_fork'
import { SYMBOLS } from '../../../../../types/interfaces'
import {
  GreasyForkBaseUserType,
  GreasyForkScriptUserType,
  GreasyForkUserType,
  ScriptClearOperationType,
  ScriptFeedbackActionType,
  ScriptStatusActionType,
  ScriptToolbarCategory,
  UpdateOperation,
} from '../../../../../user_center/tab/personalization/custom_css/theme/others/greasy_fork/module/storage_process/types'
import { GreasyFork } from '../../../../../user_center/tab/personalization/custom_css/theme/others/greasy_fork/page/lib'
import {
  BASE_USER_TAG_LABELS,
  SCRIPTS_USER_TAG_LABELS,
} from '../../../../../user_center/tab/personalization/custom_css/theme/others/greasy_fork/page/lib/types'
import { ConfigManager } from '../../../../config_manager'
import { ScriptDataMarkerType } from '../../../data_presentation/platform/greasy_fork/script_valuation/types'
import { GreasyForkScriptNavigator } from '../../../navigation/platform/greasy_fork/script_navigator'

export const SCRIPT_TAG_LABELS: ScriptTagLabelsType = {
  // 用户类型标签
  ...SCRIPTS_USER_TAG_LABELS,
  ...BASE_USER_TAG_LABELS,

  // 内容互动标签
  [ScriptFeedbackActionType.Like]: {
    value: ScriptFeedbackActionType.Like,
    label: '喜欢',
    icon: SYMBOLS.SHAPES.HEART,
    bgColor: 'linear-gradient(135deg, #FF6B6B 0%, #FF8E8E 100%)',
    textColor: '#FFFFFF',
    mutualExclusionId: ScriptFeedbackActionType.Dislike,
    shouldGenerateStyle: false,
  },
  [ScriptFeedbackActionType.Dislike]: {
    value: ScriptFeedbackActionType.Dislike,
    label: '不喜欢',
    icon: SYMBOLS.OTHERS.DISLIKE,
    bgColor: 'linear-gradient(135deg, #6D6D6D 0%, #9E9E9E 100%)',
    textColor: '#FFFFFF',
    mutualExclusionId: ScriptFeedbackActionType.Like,
    shouldGenerateStyle: false,
  },

  // 运行状态标签
  [ScriptStatusActionType.MarkSuccess]: {
    value: ScriptStatusActionType.MarkSuccess,
    label: '正常',
    icon: SYMBOLS.STATUS.SUCCESS,
    bgColor: 'linear-gradient(135deg, #4CAF50 0%, #8BC34A 100%)',
    textColor: '#FFFFFF',
    mutualExclusionId: ScriptStatusActionType.MarkFailed,
    shouldGenerateStyle: false,
  },
  [ScriptStatusActionType.MarkFailed]: {
    value: ScriptStatusActionType.MarkFailed,
    label: '已失效',
    icon: SYMBOLS.STATUS.ERROR,
    bgColor: 'linear-gradient(135deg, #F44336 0%, #E57373 100%)',
    textColor: '#FFFFFF',
    mutualExclusionId: ScriptStatusActionType.MarkSuccess,
    shouldGenerateStyle: false,
  },

  // 清除操作
  [ScriptClearOperationType.ClearTypes]: {
    value: ScriptClearOperationType.ClearTypes,
    label: '清除当前',
    icon: SYMBOLS.OTHERS.CLEAR,
    bgColor: '',
    textColor: '',
    shouldGenerateStyle: false,
  },
  [ScriptClearOperationType.ClearFeedback]: {
    value: ScriptClearOperationType.ClearFeedback,
    label: '清除当前',
    icon: SYMBOLS.OTHERS.CLEAR,
    bgColor: '',
    textColor: '',
    shouldGenerateStyle: false,
  },
  [ScriptClearOperationType.ClearRunStatus]: {
    value: ScriptClearOperationType.ClearRunStatus,
    label: '清除当前',
    icon: SYMBOLS.OTHERS.CLEAR,
    bgColor: '',
    textColor: '',
    shouldGenerateStyle: false,
  },
}

interface CategoryConfig {
  storagePath: GreasyForkStorageCategory
  attrName: ScriptDataMarkerType
  enumType: object
  clearType: ScriptClearOperationType
}

const CATEGORY_CONFIG: Record<ScriptToolbarCategory, CategoryConfig> = {
  [ScriptToolbarCategory.UserType]: {
    storagePath: 'user.types',
    attrName: ScriptDataMarkerType.MarkerTypes,
    enumType: GreasyForkUserType,
    clearType: ScriptClearOperationType.ClearTypes,
  },
  [ScriptToolbarCategory.Feedback]: {
    storagePath: 'script.liker',
    attrName: ScriptDataMarkerType.MarkerLiker,
    enumType: ScriptFeedbackActionType,
    clearType: ScriptClearOperationType.ClearFeedback,
  },
  [ScriptToolbarCategory.RunStatus]: {
    storagePath: 'script.status',
    attrName: ScriptDataMarkerType.MarkerSuccess,
    enumType: ScriptStatusActionType,
    clearType: ScriptClearOperationType.ClearRunStatus,
  },
}

interface Config {
  enabled?: boolean
}

export class GreasyForkScriptMark extends BaseModule {
  readonly id: string = 'greasy_fork_script_mark'
  readonly styleId: string = ComponentStyleId[this.name]
  isInitialized: boolean = false
  readonly supportedPlatforms: string[] = ConfigManager.getInstance().moduleSupportedPlatforms(this.name)
  private static instance: GreasyForkScriptMark
  private pageHandler: PageHandler = PageHandler.getInstance()
  private greasyForkScriptNavigator: GreasyForkScriptNavigator = GreasyForkScriptNavigator.getInstance()
  private toolbars = new Map<string, Toolbar>()
  private readonly itemFullSelector = `#browse-script-list li[data-script-id]`
  private readonly userLinkSelector = `dd.script-list-author a`

  config: Config = {
    enabled: true,
  }

  get name(): ComponentStyleIdType {
    return 'GreasyForkScriptMark'
  }

  /**
   * 获取单例实例
   */
  public static getInstance(): GreasyForkScriptMark {
    if (!GreasyForkScriptMark.instance) {
      GreasyForkScriptMark.instance = new GreasyForkScriptMark()
    }
    return GreasyForkScriptMark.instance
  }

  destroy(): void {
    try {
      // 1. 清除工具栏实例
      this.toolbars.forEach((toolbar) => {
        toolbar.destroy()
      })
      this.toolbars.clear()

      // 2. 重置状态
      this.isInitialized = false

      super.destroy()
    }
    catch (error: any) {
      logger.error(`[${this.name}] Error occurred during module destruction:`, error)
    }
    finally {
      // 清理数据属性
      $(GREASY_FORK_PAGE_ELEMENTS.RESULT_WRAPPER.selector).removeData('has-toolbar')
    }
  }

  core(): void {
    this.loadConfig()

    if (!this.config.enabled)
      return

    this.renderToolbar()
    this.addTag()
  }

  onToggleCallback(_id: string, checked: boolean): void {
    super.onToggleCallback(_id, checked)
  }

  /**
   * 渲染工具栏
   */
  private renderToolbar() {
    const selector = this.pageHandler.services.greasyFork.getScriptListSelector()
    const $target = $(selector)

    if (!$target || !$target.length) {
      loggerDeduplicator.error(`[${this.name}] 没有找到脚本列表元素：${selector}`)
      return
    }

    $target.each((_, element) => {
      const $script = $(element)

      if ($script.data(BodyClasses.HAS_TOOLBAR))
        return

      const scriptId = GreasyFork.getCurrentScriptIdFromList($script)
      const userId = this.pageHandler.services.greasyFork.getUserId($script.find(this.userLinkSelector))

      if (!scriptId || scriptId.length === 0 || !userId || userId.length === 0)
        return

      const toolbar = this.initToolbar()
      $script.append(toolbar.render())
      toolbar.mount($script)
      $script.data(BodyClasses.HAS_TOOLBAR, true)

      // 存储工具栏实例
      this.toolbars.set(scriptId, toolbar)

      // 更新标记
      this.updateElementUI($script, userId, ScriptToolbarCategory.UserType)
      this.updateElementUI($script, scriptId, ScriptToolbarCategory.Feedback)
      this.updateElementUI($script, scriptId, ScriptToolbarCategory.RunStatus)
      // 处理工具栏菜单可见性
      this.handleToolbarMenuVisibility($script, scriptId, userId)
    })
  }

  private handleToolbarMenuVisibility($element: JQuery, id: string, userId: string): void {
    // 遍历所有分类配置
    Object.entries(CATEGORY_CONFIG).forEach(([_, config]) => {
      // 检查是否存在该分类的标记
      const hasMark = Object.values(
        this.pageHandler.storages.greasyFork.getStatus(config.clearType === ScriptClearOperationType.ClearTypes ? userId : id, config.storagePath),
      ).some(Boolean)

      // 更新对应清除按钮的显示状态
      $element.find(`.toolbar [data-id="${config.clearType}"]`)
        .toggleClass('deactivate', !hasMark)
    })
  }

  /**
   * 创建处理函数映射
   * @param enumObj 枚举对象
   * @param category 反馈分类
   */
  private createHandlerMap = <T extends ScriptActionType>(
    enumObj: Record<string, T>,
    category: ScriptToolbarCategory,
  ): ActionHandler =>
    Object.values(enumObj).reduce((acc, key) => ({
      ...acc,
      [key]: (event: JQuery.ClickEvent) => {
        this.handleUserAction(event, key, category)
      },
    }), {} as ActionHandler)

  private initToolbar(): Toolbar {
    // 合并所有处理函数
    const actionHandlers: any = {
      ...this.createHandlerMap(GreasyForkUserType, ScriptToolbarCategory.UserType),
      ...this.createHandlerMap(ScriptFeedbackActionType, ScriptToolbarCategory.Feedback),
      ...this.createHandlerMap(ScriptStatusActionType, ScriptToolbarCategory.RunStatus),
      ...{
        [ScriptClearOperationType.ClearTypes]: (event: JQuery.ClickEvent) => {
          this.handleClearAction(event, ScriptToolbarCategory.UserType)
        },
        [ScriptClearOperationType.ClearFeedback]: (event: JQuery.ClickEvent) => {
          this.handleClearAction(event, ScriptToolbarCategory.Feedback)
        },
        [ScriptClearOperationType.ClearRunStatus]: (event: JQuery.ClickEvent) => {
          this.handleClearAction(event, ScriptToolbarCategory.RunStatus)
        },
      },
    }

    const menus = [
      {
        id: ScriptToolbarCategory.UserType,
        icon: SYMBOLS.UI.TAG,
        text: '用户身份',
        children: [
          GreasyForkScriptUserType.SuperCreator,
          GreasyForkBaseUserType.ActiveUser,
          GreasyForkBaseUserType.LoyalFan,
          GreasyForkBaseUserType.Blacklisted,
          ScriptClearOperationType.ClearTypes,
        ].map(key => ({
          id: key,
          text: SCRIPT_TAG_LABELS[key].label,
          icon: SCRIPT_TAG_LABELS[key].icon,
          onClick: (_menu: MenuItem, event: JQuery.ClickEvent) => {
            actionHandlers[key](event)
          },
        })),
      },
      {
        id: ScriptToolbarCategory.Feedback,
        icon: SYMBOLS.USER.NERD,
        text: '内容互动',
        children: [
          ScriptFeedbackActionType.Like,
          ScriptFeedbackActionType.Dislike,
          ScriptClearOperationType.ClearFeedback,
        ].map(key => ({
          id: key,
          text: SCRIPT_TAG_LABELS[key].label,
          icon: SCRIPT_TAG_LABELS[key].icon,
          mutualExclusionId: SCRIPT_TAG_LABELS[key].mutualExclusionId,
          onClick: (_menu: MenuItem, event: JQuery.ClickEvent) => {
            actionHandlers[key](event)
          },
        })),
      },
      {
        id: ScriptToolbarCategory.RunStatus,
        icon: SYMBOLS.OTHERS.ROCKET,
        text: '运行状态',
        children: [
          ScriptStatusActionType.MarkSuccess,
          ScriptStatusActionType.MarkFailed,
          ScriptClearOperationType.ClearRunStatus,
        ].map(key => ({
          id: key,
          text: SCRIPT_TAG_LABELS[key].label,
          icon: SCRIPT_TAG_LABELS[key].icon,
          mutualExclusionId: SCRIPT_TAG_LABELS[key].mutualExclusionId,
          onClick: (_menu: MenuItem, event: JQuery.ClickEvent) => {
            actionHandlers[key](event)
          },
        })),
      },
    ]

    return new Toolbar({
      id: MODULE_CONFIG.PLATFORM.greasyFork.toolbarId.script,
      menus,
    })
  }

  private handleUserAction(event: JQuery.ClickEvent, actionType: ScriptActionType, category: ScriptToolbarCategory): void {
    const $element = $(event.currentTarget)
    const $scriptItem = $element.closest('li')
    const scriptId = GreasyFork.getCurrentScriptIdFromList($scriptItem)

    const $userLink = $scriptItem.find(this.userLinkSelector)
    const userId = this.pageHandler.services.greasyFork.getUserId($userLink)
    const id = category === ScriptToolbarCategory.UserType ? userId : scriptId

    const userName = $userLink.text().trim()
    const scriptTitle = $scriptItem.find('.script-link').text().trim()
    const remark = category === ScriptToolbarCategory.UserType ? userName : scriptTitle

    if (!id || id.length === 0)
      return

    try {
      this.handleAction(this.getToolbarMenuItem(event, category), $scriptItem, actionType, category, id, 'maker', remark)
    }
    catch (error: any) {
      logger.warn(`[${this.name}] ${actionType} 操作失败: ${error.message}`)
    }
  }

  private handleClearAction(target: JQuery.ClickEvent | JQuery<HTMLElement>, category: ScriptToolbarCategory): void {
    const $element = 'currentTarget' in target
      ? $(target.currentTarget)
      : target

    const $scriptItem = $element.closest('li')
    const scriptId = GreasyFork.getCurrentScriptIdFromList($scriptItem)

    const $userLink = $scriptItem.find(this.userLinkSelector)
    const userId = this.pageHandler.services.greasyFork.getUserId($userLink)
    const id = category === ScriptToolbarCategory.UserType ? userId : scriptId

    const userName = $userLink.text().trim()
    const scriptTitle = $scriptItem.find('.script-link').text().trim()
    const remark = category === ScriptToolbarCategory.UserType ? userName : scriptTitle

    if (!id || id.length === 0)
      return

    try {
      this.handleAction(this.getToolbarMenuItem(target, category), $scriptItem, null, category, id, 'clear', remark)

      logger.debug(`[${this.name}] 已清除脚本 id='${scriptId}' 的'${category}'标记`)
    }
    catch (error: any) {
      logger.warn(`[${this.name}] 清除脚本 id='${scriptId}' 的'${category}'标记失败: ${error.message}`)
    }
  }

  handleAction(
    $toolbarMenu: JQuery,
    $scriptItem: JQuery,
    actionType: ScriptActionType | null,
    category: ScriptToolbarCategory,
    id: string,
    type: 'clear' | 'maker',
    remark: string = '',
  ): void {
    const config = CATEGORY_CONFIG[category]

    // 1-1. 批量清除存储状态
    if (type === 'clear') {
      Object.values(config.enumType).forEach((statType) => {
        this.pageHandler.storages.greasyFork.updateStorageItem(config.storagePath, statType, id, UpdateOperation.Remove, remark)
      })
    }
    // 1-2. 更新存储状态
    else if (type === 'maker') {
      this.pageHandler.storages.greasyFork.updateStorageItem(config.storagePath, actionType!, id, UpdateOperation.Add, remark)
    }

    // 2. 更新UI
    this.updateElementUI($scriptItem, id, category)
    this.updateToolbarMenu($toolbarMenu, category)

    // 3. 更新标签
    this.addTag()

    // 4. 刷新导航数据
    this.greasyForkScriptNavigator.refresh()
  }

  /**
   * 更新元素 UI
   */
  private updateElementUI($element: JQuery, id: string, category: ScriptToolbarCategory): void {
    const config = CATEGORY_CONFIG[category]
    const storageData = this.pageHandler.storages.greasyFork.getStatus(id, config.storagePath)
    const trueConfig = Object.entries(storageData)
      .filter(([_, value]) => value)
      .map(([key]) => key)

    if (trueConfig.length === 0) {
      // 移除数据属性
      $element.removeAttr(config.attrName)
      // 移除用户徽章
      Object.values(GreasyForkUserType).forEach((userType) => {
        $element.find(`.user-badge.${userType}`).remove()
      })
      return
    }

    $element.attr(config.attrName, trueConfig[0])
  }

  private updateToolbarMenu($submenu: JQuery, category: ScriptToolbarCategory): void {
    const deactivateClassName = 'deactivate'

    // 清除按钮元素
    const clearSelector = Object.values(ScriptClearOperationType)
      .map(item => `[data-id="${item}"]`)
      .join(',')
    const $clearElement = $submenu.find(clearSelector)

    // 已标识元素
    let markerSelector = ''
    switch (category) {
      case ScriptToolbarCategory.UserType:
        markerSelector = `[${ScriptDataMarkerType.MarkerTypes}]`
        break
      case ScriptToolbarCategory.Feedback:
        markerSelector = `[${ScriptDataMarkerType.MarkerLiker}]`
        break
      case ScriptToolbarCategory.RunStatus:
        markerSelector = `[${ScriptDataMarkerType.MarkerSuccess}]`
        break
    }
    const $item = $submenu.closest('li[data-script-id]').filter(markerSelector)

    // 根据是否标识来更新清除按钮显示状态
    $clearElement.toggleClass(deactivateClassName, !$item?.length)
  }

  /**
   * 添加标签
   */
  private addTag() {
    $(this.itemFullSelector).each((_, element) => {
      const $element = $(element)

      // 处理用户标签
      this.pageHandler.services.greasyFork.handleUserTag($element, this.userLinkSelector)
    })
  }

  /**
   * 获取工具栏一级菜单元素
   */
  getToolbarMenuItem(target: JQuery.ClickEvent | JQuery<HTMLElement>, category: ScriptToolbarCategory): JQuery {
    const isClickEvent = 'currentTarget' in target

    if (isClickEvent)
      return $(target.currentTarget).closest('.toolbar-submenu')

    let menuId: ScriptClearOperationType | null = null

    switch (category) {
      case ScriptToolbarCategory.UserType:
        menuId = ScriptClearOperationType.ClearTypes
        break
      case ScriptToolbarCategory.Feedback:
        menuId = ScriptClearOperationType.ClearFeedback
        break
      case ScriptToolbarCategory.RunStatus:
        menuId = ScriptClearOperationType.ClearRunStatus
    }

    return target.find(`.toolbar-submenu:has(.toolbar-submenu-item[data-id="${menuId}"])`) || $()
  }

  applyConfig(config: Partial<Config>): void {
    super.updateConfig(config)

    this.renderToolbar()

    logger.info(`[${this.name}] Config updated and apply`, this.config)
  }

  getStyles(): string {
    return ``
  }
}
